<!DOCTYPE html>
<!--
Copyright 2017 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->

<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/extras/importer/linux_perf/ftrace_importer.html">
<link rel="import" href="/tracing/extras/importer/trace_event_importer.html">
<link rel="import" href="/tracing/metrics/android_systrace_metric.html">
<link rel="import" href="/tracing/value/histogram_set.html">

<script>
'use strict';

tr.b.unittest.testSuite(function() {
  const SYSTRACE_CLOCK_SYNC =
      '<100>-100 (-----) [000] ...1  0.000000: tracing_mark_write: ' +
      'trace_event_clock_sync: parent_ts=0\n' +
      '<100>-100 (-----) [000] ...1  0.000000: tracing_mark_write: ' +
      'trace_event_clock_sync: realtime_ts=1487002000000';

  // Some event is required to help importer detect a parent process.
  const SYSTRACE_SYSTEM_SERVER_ANNOTATION =
      'system_server-101 (  101) [000] ...1  0.550000: ' +
      'tracing_mark_write: S|101|dummyEvent|201\n' +
      'system_server-101 (  101) [000] ...1  0.551000: ' +
      'tracing_mark_write: F|101|dummyEvent|201';

  const SYSTRACE_TOUCH_SLICE =
      'com.android.systemui-102 (  102) [000] ...1  2.500000: ' +
      'tracing_mark_write: S|102|deliverInputEvent|202\n' +
      'com.android.systemui-102 (  102) [000] ...1  2.510000: ' +
      'tracing_mark_write: F|102|deliverInputEvent|202';

  const SYSTRACE_LAUNCH_SLICE =
      'Binder:101_C-103 (  101) [000] ...1  2.750000: ' +
      'tracing_mark_write: S|101|launching: com.android.apps.sms|203\n' +
      'android.display-104 (  101) [000] ...1  4.250000: ' +
      'tracing_mark_write: F|101|launching: com.android.apps.sms|203';

  const SYSTRACE_DRAW_SLICE =
      'com.android.apps.sms-105 (  105) [000] ...1  4.450000: ' +
      'tracing_mark_write: B|105|draw\n' +
      'com.android.apps.sms-105 (  105) [000] ...1  4.455000: ' +
      'tracing_mark_write: E';

  function makeModel(systraceLines) {
    const events = JSON.stringify({
      traceEvents: [],
      systemTraceEvents: SYSTRACE_CLOCK_SYNC + '\n' + systraceLines.join('\n')
    });
    const model = tr.c.TestUtils.newModelWithEvents([events]);
    // Fix missing process names.
    for (const pid in model.processes) {
      const process = model.processes[pid];
      if (process.name !== undefined) continue;
      if (process.threads[pid] !== undefined) {
        process.name = process.threads[pid].name;
      }
    }
    return model;
  }

  function testStartup(systrace, expectedTimeInMs) {
    const histograms = new tr.v.HistogramSet();
    tr.metrics.sh.androidSystraceMetric(histograms, makeModel(systrace));
    assert.lengthOf(histograms, 1);
    const startupHist = histograms.getHistogramNamed(
        'android:systrace:startup:com.android.apps.sms').running;
    assert.strictEqual(startupHist.count, 1);
    assert.closeTo(startupHist.mean, expectedTimeInMs, 1e-5);
  }

  test('androidSystraceMetric_startup_noData', function() {
    const histograms = new tr.v.HistogramSet();
    tr.metrics.sh.androidSystraceMetric(histograms, makeModel([]));
    assert.lengthOf(histograms, 0);
  });

  test('androidSystraceMetric_startup_simple', function() {
    const systrace = [
      SYSTRACE_SYSTEM_SERVER_ANNOTATION,
      SYSTRACE_TOUCH_SLICE,
      SYSTRACE_LAUNCH_SLICE,
      SYSTRACE_DRAW_SLICE
    ];
    testStartup(systrace, 1955);
  });

  test('androidSystraceMetric_startup_noTouch', function() {
    const systrace = [
      SYSTRACE_SYSTEM_SERVER_ANNOTATION,
      SYSTRACE_LAUNCH_SLICE,
      SYSTRACE_DRAW_SLICE
    ];
    testStartup(systrace, 1705);
  });

  test('androidSystraceMetric_startup_noDraw', function() {
    const systrace = [
      SYSTRACE_SYSTEM_SERVER_ANNOTATION,
      SYSTRACE_TOUCH_SLICE,
      SYSTRACE_LAUNCH_SLICE,
    ];
    testStartup(systrace, 1750);
  });

  test('androidSystraceMetric_startup_noTouchNoDraw', function() {
    const systrace = [
      SYSTRACE_SYSTEM_SERVER_ANNOTATION,
      SYSTRACE_LAUNCH_SLICE,
    ];
    testStartup(systrace, 1500);
  });

  test('androidSystraceMetric_threadtime_simple', function() {
    const model = tr.c.TestUtils.newModel(model => {
      const process = model.getOrCreateProcess(42);
      process.name = 'garbage_producer';
      const thread = process.getOrCreateThread(42);
      thread.timeSlices = [
        tr.c.TestUtils.newThreadSlice(thread, 'Sleeping', 0, 100),
        tr.c.TestUtils.newThreadSlice(thread, 'Running', 100, 400)
      ];
    });

    const histograms = new tr.v.HistogramSet();
    tr.metrics.sh.androidSystraceMetric(histograms, model);
    assert.lengthOf(histograms, 5);

    const assertHistValue = function(name, expectedValue) {
      const hist = histograms.getHistogramNamed(
          `android:systrace:threadtime:garbage_producer:${name}`);
      assert.strictEqual(hist.running.count, 1);
      assert.closeTo(hist.running.mean, expectedValue, 1e-5);
    };
    assertHistValue('running', 0.8);
    assertHistValue('runnable', 0);
    assertHistValue('sleeping', 0.2);
    assertHistValue('blockio', 0);
    assertHistValue('uninterruptible', 0);
  });
});
</script>
